package com.wyix;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 代码关键逻辑说明
 * 线程池限流参数：
 * <p>
 * corePoolSize=3：平时保持3个线程处理请求（核心服务能力）。
 * maxPoolSize=5：当请求激增时，最多扩展到5个线程（紧急扩容能力）。
 * queueCapacity=10：超过线程数的请求先在队列中等待（缓冲能力）。
 * 总负载上限 = 最大线程数 + 队列容量 = 5 + 10 = 15，即最多同时处理15个请求，超过则触发拒绝策略。
 * 拒绝策略： 使用AbortPolicy（默认策略），当线程池+队列满时，直接抛出RejectedExecutionException，提示用户“系统繁忙”。
 * <p>
 * 库存安全： 使用AtomicInteger保证多线程下库存扣减的原子性，避免超卖。
 */
public class SeckillWithThreadPool2 {
    // 模拟库存（原子类保证线程安全）
    private static final AtomicInteger STOCK = new AtomicInteger(30);

    public static void main(String[] args) {
        // 线程池配置（限流核心参数）
        int corePoolSize = 3;       // 核心线程数：同时处理的最大正常请求数
        int maxPoolSize = 5;        // 最大线程数：紧急情况下可扩展的线程数
        long keepAliveTime = 60;    // 空闲线程存活时间（秒）
        // 注意：不设置队列容量，使用无界队列
        // int queueCapacity = 10;     // 等待队列容量：暂时排队的请求数

        // 创建线程池（使用无界队列，不会触发拒绝策略）
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS,
                // 使用无界队列 LinkedBlockingQueue，不指定容量
                new LinkedBlockingQueue<>()
                // 移除拒绝策略参数，使用默认的 DiscardPolicy 也可，不过无界队列不会触发拒绝
        );

        // 模拟100个用户同时发起秒杀请求（远超线程池负载）
        for (int i = 0; i < 100; i++) {
            int userId = i + 1;
            try {
                threadPool.execute(() -> seckill(userId));
                System.out.println("用户" + userId + "请求已加入处理队列");
            } catch (RejectedExecutionException e) {
                System.out.println("用户" + userId + "请求被拒绝（系统繁忙）");
            }
        }

        // 关闭线程池（实际生产中需根据业务场景合理管理）
        threadPool.shutdown();
    }

    // 秒杀核心逻辑
    private static void seckill(int userId) {
        try {
            // 模拟业务处理耗时（500ms）
            Thread.sleep(500);

            // 检查库存并扣减
            if (STOCK.get() > 0) {
                int newStock = STOCK.decrementAndGet();
                System.out.println("用户" + userId + "秒杀成功！剩余库存：" + newStock);
            } else {
                System.out.println("用户" + userId + "秒杀失败：库存已售罄");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}